Skip to content

refactor: migrate all .tpl.php/.sub.php/.inc.php templates to Blade#3362

Merged
marcelfolaron merged 7 commits into
masterfrom
refactor/tpl-to-blade-migration
May 27, 2026
Merged

refactor: migrate all .tpl.php/.sub.php/.inc.php templates to Blade#3362
marcelfolaron merged 7 commits into
masterfrom
refactor/tpl-to-blade-migration

Conversation

@marcelfolaron

Copy link
Copy Markdown
Collaborator

Summary

Converts all remaining legacy template files to Blade, completing the frontend template unification started with the Dashboard, Menu, Tickets modal, and Canvas (Goalcanvas) domains.

  • 272 legacy files removed: all .tpl.php, .sub.php, and .inc.php files across Domain and Plugin directories
  • 200 Blade files added (net reduction of 72 files — many thin delegate templates collapsed to single @include lines)

What was converted

Phase Scope Files
Canvas base Canvas:: shared templates (was .inc.php) 10
Canvas domains 16 canvas domains × 5 templates 80
Help Canvas help delegates + static content 29
Shared submodules Tickets (15), Comments, Files, Projects, Connector 20
Simple domains Api, Auth, CsvImport, Errors, Files, Install, Reports, Setting, Sprints, Strategy, TwoFA 18
Medium domains Calendar, Clients, Connector, Ideas, Timesheets, Users, Wiki 49
Complex domains Tickets (15) + Projects (7) 22
Plugins Accounts, Billing, Llamadorian, PgmPro, StrategyPro, Whiteboardscanvas 39

Key conventions enforced

Translation escaping — language strings in Leantime frequently contain HTML (icon <span>/<i> tags, links). The rule applied throughout:

  • {!! __('key') !!} — all visible text content (unescaped, language strings may contain HTML)
  • {{ __('key') }} — only inside HTML attribute values (value="", placeholder="", data-tippy-content="")

Other patterns:

  • $tpl->get('key') → direct $key variable (passed by view data)
  • $tpl->e() / $tpl->escape(){{ $var }} (auto-escaped)
  • $tpl->escapeMinimal() / $tpl->displayNotification(){!! !!}
  • $tpl->displaySubmodule('x-y')@include('x::submodules.y')
  • $tpl->dispatchTplEvent('name')@dispatchEvent('name')
  • Session CSRF tokens → @csrf
  • Inline <script> blocks → @once @push('scripts') / @endpush @endonce
  • PHP control structures → @if / @foreach / @else etc.

Testing

  • Unit tests: 122/122 passing (no regressions)
  • Acceptance tests: pre-existing InstallCest failure unrelated to this change (requires a clean DB; fails when run against an already-installed instance)

Notes

  • leantime-cloud will need to receive the same changes separately (mirrored repo)
  • The ViewsServiceProvider extension priority (.blade.php > .tpl.php) means the old files were already overridden before deletion — this PR simply removes the dead code

Convert 272 legacy template files across Domain and Plugin directories to
Blade (.blade.php), removing all .tpl.php, .sub.php, and .inc.php files.

Changes:
- Canvas base templates (10): showCanvasTop, showCanvasBottom, canvasDialog,
  canvasComment, delCanvas, delCanvasItem, element, modals, helper, boardDialog
- Canvas domain wrappers (80): 16 canvas domains x 5 templates each
- Help templates (29): canvas help delegates and static help content
- Shared submodules (20): Tickets (15), Comments, Files, Projects, Connector
- Domain templates (89): Api, Auth, Calendar, Clients, Comments, Connector,
  CsvImport, Errors, Files, Ideas, Install, Reports, Setting, Sprints,
  Strategy, Timesheets, TwoFA, Users, Wiki
- Tickets and Projects (22): full conversion including kanban, roadmap,
  showTicket, showAll, milestones, and all modal dialogs
- Plugin templates (39): Accounts, Billing, Llamadorian, PgmPro,
  StrategyPro, Whiteboardscanvas

Translation escaping: use {!! __() !!} for all visible text (language strings
may contain HTML/icons); {{ __() }} only inside HTML attribute values
(value=, placeholder=, data-tippy-content=).
@marcelfolaron marcelfolaron requested a review from a team as a code owner April 12, 2026 17:35
@marcelfolaron marcelfolaron requested review from broskees and Copilot and removed request for a team April 12, 2026 17:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Migrates remaining legacy PHP templates (.tpl.php, .sub.php, .inc.php) to Blade to complete template unification across domains (Canvas variants, Projects, Connector, Auth/Install, etc.).

Changes:

  • Removed legacy delegate templates and replaced them with Blade equivalents (many collapsed to @include).
  • Converted full-page templates to Blade layout sections (@extends($layout), @section('content')), and moved inline scripts into @once @push('scripts') in some places.
  • Updated translation/output patterns to Blade escaping conventions and introduced new shared Canvas partials (e.g., canvas::helper, canvas::showCanvasBottom).

Reviewed changes

Copilot reviewed 297 out of 429 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
app/Domain/Smcanvas/Templates/delCanvasItem.tpl.php Removes legacy delegate template for canvas item deletion modal.
app/Domain/Smcanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared canvas deletion modal.
app/Domain/Smcanvas/Templates/delCanvas.tpl.php Removes legacy delegate template for canvas deletion modal.
app/Domain/Smcanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared canvas deletion modal.
app/Domain/Smcanvas/Templates/canvasDialog.tpl.php Removes legacy delegate template for canvas dialog modal.
app/Domain/Smcanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared canvas dialog modal.
app/Domain/Smcanvas/Templates/canvasComment.tpl.php Removes legacy delegate template for canvas comment modal.
app/Domain/Smcanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared canvas comment modal.
app/Domain/Setting/Templates/editBoxDialog.tpl.php Removes legacy settings label edit modal template.
app/Domain/Setting/Templates/editBoxDialog.blade.php Adds Blade version of settings label edit modal.
app/Domain/Sbcanvas/Templates/showCanvas.blade.php Adds Blade implementation of Strategy Brief canvas rendering.
app/Domain/Sbcanvas/Templates/delCanvasItem.tpl.php Removes Strategy Brief legacy delegate delete-item template.
app/Domain/Sbcanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Sbcanvas/Templates/delCanvas.tpl.php Removes Strategy Brief legacy delegate delete-canvas template.
app/Domain/Sbcanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Sbcanvas/Templates/canvasDialog.tpl.php Removes Strategy Brief legacy delegate dialog template.
app/Domain/Sbcanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Sbcanvas/Templates/canvasComment.tpl.php Removes Strategy Brief legacy delegate comment template.
app/Domain/Sbcanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/Riskscanvas/Templates/showCanvas.tpl.php Removes legacy Risks canvas template.
app/Domain/Riskscanvas/Templates/showCanvas.blade.php Adds Blade implementation of Risks canvas.
app/Domain/Riskscanvas/Templates/delCanvasItem.tpl.php Removes legacy Risks delegate delete-item template.
app/Domain/Riskscanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Riskscanvas/Templates/delCanvas.tpl.php Removes legacy Risks delegate delete-canvas template.
app/Domain/Riskscanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Riskscanvas/Templates/canvasDialog.tpl.php Removes legacy Risks delegate dialog template.
app/Domain/Riskscanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Riskscanvas/Templates/canvasComment.tpl.php Removes legacy Risks delegate comment template.
app/Domain/Riskscanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/Retroscanvas/Templates/showCanvas.tpl.php Removes legacy Retros canvas template.
app/Domain/Retroscanvas/Templates/showCanvas.blade.php Adds Blade implementation of Retros canvas.
app/Domain/Retroscanvas/Templates/delCanvasItem.tpl.php Removes legacy Retros delegate delete-item template.
app/Domain/Retroscanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Retroscanvas/Templates/delCanvas.tpl.php Removes legacy Retros delegate delete-canvas template.
app/Domain/Retroscanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Retroscanvas/Templates/canvasDialog.tpl.php Removes legacy Retros delegate dialog template.
app/Domain/Retroscanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Retroscanvas/Templates/canvasComment.tpl.php Removes legacy Retros delegate comment template.
app/Domain/Retroscanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/Projects/Templates/submodules/tickets.blade.php Converts submodule inline PHP to Blade-compatible variable usage.
app/Domain/Projects/Templates/showAll.tpl.php Removes legacy “all projects” template.
app/Domain/Projects/Templates/showAll.blade.php Adds Blade “all projects” page template and pushes scripts.
app/Domain/Projects/Templates/editProject.blade.php Adds Blade template placeholder for edit project.
app/Domain/Projects/Templates/editAccount.blade.php Adds Blade template placeholder for edit account.
app/Domain/Projects/Templates/duplicateProject.tpl.php Removes legacy duplicate-project modal template.
app/Domain/Projects/Templates/duplicateProject.blade.php Adds Blade duplicate-project modal template.
app/Domain/Projects/Templates/delProject.tpl.php Removes legacy delete-project template.
app/Domain/Projects/Templates/delProject.blade.php Adds Blade delete-project page template.
app/Domain/Install/Templates/update.tpl.php Removes legacy update DB template.
app/Domain/Install/Templates/update.blade.php Adds Blade template for update DB flow.
app/Domain/Install/Templates/new.tpl.php Removes legacy installer template.
app/Domain/Install/Templates/new.blade.php Adds Blade installer template.
app/Domain/Insightscanvas/Templates/showCanvas.tpl.php Removes legacy Insights canvas template.
app/Domain/Insightscanvas/Templates/showCanvas.blade.php Adds Blade implementation of Insights canvas.
app/Domain/Insightscanvas/Templates/delCanvasItem.tpl.php Removes legacy Insights delegate delete-item template.
app/Domain/Insightscanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Insightscanvas/Templates/delCanvas.tpl.php Removes legacy Insights delegate delete-canvas template.
app/Domain/Insightscanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Insightscanvas/Templates/canvasDialog.tpl.php Removes legacy Insights delegate dialog template.
app/Domain/Insightscanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Insightscanvas/Templates/canvasComment.tpl.php Removes legacy Insights delegate comment template.
app/Domain/Insightscanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/Ideas/Templates/delCanvasItem.tpl.php Removes legacy Ideas delete-item modal template.
app/Domain/Ideas/Templates/delCanvasItem.blade.php Adds Blade Ideas delete-item modal template.
app/Domain/Ideas/Templates/delCanvas.tpl.php Removes legacy Ideas delete-board template.
app/Domain/Ideas/Templates/delCanvas.blade.php Adds Blade Ideas delete-board template.
app/Domain/Help/Templates/wiki.blade.php Removes legacy bootstrap PHP extraction and inlines SVG output via Blade.
app/Domain/Help/Templates/swotCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/swotCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/sqCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/sqCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/smCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/smCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/simpleLeanCanvas.tpl.php Removes legacy simple lean helper template.
app/Domain/Help/Templates/simpleLeanCanvas.blade.php Adds Blade version of simple lean helper template.
app/Domain/Help/Templates/showProjects.blade.php Removes legacy bootstrap PHP extraction and converts translations to Blade.
app/Domain/Help/Templates/showClients.tpl.php Removes legacy show-clients helper template.
app/Domain/Help/Templates/showClients.blade.php Adds Blade show-clients helper template.
app/Domain/Help/Templates/sbCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/sbCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/risksCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/risksCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/retrosCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/retrosCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/projectSuccess.tpl.php Removes legacy project-success helper template.
app/Domain/Help/Templates/projectSuccess.blade.php Adds Blade project-success helper template.
app/Domain/Help/Templates/obmCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/obmCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/notfound.tpl.php Removes legacy not-found helper template.
app/Domain/Help/Templates/notfound.blade.php Adds Blade not-found helper template.
app/Domain/Help/Templates/newProject.tpl.php Removes legacy new-project helper template.
app/Domain/Help/Templates/newProject.blade.php Adds Blade new-project helper template.
app/Domain/Help/Templates/mytimesheets.tpl.php Removes legacy timesheets helper template.
app/Domain/Help/Templates/mytimesheets.blade.php Adds Blade timesheets helper template.
app/Domain/Help/Templates/minempathyCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/minempathyCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/leanCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/leanCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/lbmCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/lbmCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/insightsCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/insightsCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/ideationBoard.tpl.php Removes legacy ideation helper template.
app/Domain/Help/Templates/ideationBoard.blade.php Adds Blade ideation helper template.
app/Domain/Help/Templates/ideaBoard.tpl.php Removes legacy idea-board helper template.
app/Domain/Help/Templates/ideaBoard.blade.php Adds Blade idea-board helper template.
app/Domain/Help/Templates/fullLeanCanvas.tpl.php Removes legacy full lean helper template.
app/Domain/Help/Templates/fullLeanCanvas.blade.php Adds Blade full lean helper template.
app/Domain/Help/Templates/emCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/emCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/eaCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/eaCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/dbmCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/dbmCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/cpCanvas.tpl.php Removes legacy helper include delegate.
app/Domain/Help/Templates/cpCanvas.blade.php Adds Blade include wrapper to shared canvas::helper.
app/Domain/Help/Templates/blueprints.blade.php Removes legacy bootstrap PHP extraction and converts BASE_URL usage to Blade.
app/Domain/Help/Templates/backlog.tpl.php Removes legacy backlog helper template.
app/Domain/Help/Templates/backlog.blade.php Adds Blade backlog helper template.
app/Domain/Help/Templates/advancedBoards.tpl.php Removes legacy advanced-boards helper template.
app/Domain/Help/Templates/advancedBoards.blade.php Adds Blade advanced-boards helper template.
app/Domain/Errors/Templates/error501.tpl.php Removes legacy 501 error template.
app/Domain/Errors/Templates/error501.blade.php Adds Blade 501 error template.
app/Domain/Errors/Templates/error500.tpl.php Removes legacy 500 error template.
app/Domain/Errors/Templates/error500.blade.php Adds Blade 500 error template.
app/Domain/Errors/Templates/error404.tpl.php Removes legacy 404 error template.
app/Domain/Errors/Templates/error404.blade.php Adds Blade 404 error template.
app/Domain/Errors/Templates/error403.tpl.php Removes legacy 403 error template.
app/Domain/Errors/Templates/error403.blade.php Adds Blade 403 error template.
app/Domain/Emcanvas/Templates/showCanvas.blade.php Adds Blade implementation for Empathy Map canvas.
app/Domain/Emcanvas/Templates/delCanvasItem.tpl.php Removes legacy Empathy Map delegate delete-item template.
app/Domain/Emcanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Emcanvas/Templates/delCanvas.tpl.php Removes legacy Empathy Map delegate delete-canvas template.
app/Domain/Emcanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Emcanvas/Templates/canvasDialog.tpl.php Removes legacy Empathy Map delegate dialog template.
app/Domain/Emcanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Emcanvas/Templates/canvasComment.tpl.php Removes legacy Empathy Map delegate comment template.
app/Domain/Emcanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/Eacanvas/Templates/showCanvas.tpl.php Removes legacy EA canvas template.
app/Domain/Eacanvas/Templates/showCanvas.blade.php Adds Blade implementation of EA canvas.
app/Domain/Eacanvas/Templates/delCanvasItem.tpl.php Removes legacy EA delegate delete-item template.
app/Domain/Eacanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Eacanvas/Templates/delCanvas.tpl.php Removes legacy EA delegate delete-canvas template.
app/Domain/Eacanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Eacanvas/Templates/canvasDialog.tpl.php Removes legacy EA delegate dialog template.
app/Domain/Eacanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Eacanvas/Templates/canvasComment.tpl.php Removes legacy EA delegate comment template.
app/Domain/Eacanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/Dbmcanvas/Templates/showCanvas.blade.php Adds Blade implementation of DBM canvas.
app/Domain/Dbmcanvas/Templates/delCanvasItem.tpl.php Removes legacy DBM delegate delete-item template.
app/Domain/Dbmcanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Dbmcanvas/Templates/delCanvas.tpl.php Removes legacy DBM delegate delete-canvas template.
app/Domain/Dbmcanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Dbmcanvas/Templates/canvasDialog.tpl.php Removes legacy DBM delegate dialog template.
app/Domain/Dbmcanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Dbmcanvas/Templates/canvasComment.tpl.php Removes legacy DBM delegate comment template.
app/Domain/Dbmcanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/CsvImport/Templates/upload.blade.php Converts CSV upload page to Blade layout and pushes scripts.
app/Domain/Cpcanvas/Templates/delCanvasItem.tpl.php Removes legacy CP delegate delete-item template.
app/Domain/Cpcanvas/Templates/delCanvasItem.blade.php Adds Blade include wrapper for shared delete-item template.
app/Domain/Cpcanvas/Templates/delCanvas.tpl.php Removes legacy CP delegate delete-canvas template.
app/Domain/Cpcanvas/Templates/delCanvas.blade.php Adds Blade include wrapper for shared delete-canvas template.
app/Domain/Cpcanvas/Templates/canvasDialog.tpl.php Removes legacy CP delegate dialog template.
app/Domain/Cpcanvas/Templates/canvasDialog.blade.php Adds Blade include wrapper for shared dialog template.
app/Domain/Cpcanvas/Templates/canvasComment.tpl.php Removes legacy CP delegate comment template.
app/Domain/Cpcanvas/Templates/canvasComment.blade.php Adds Blade include wrapper for shared comment template.
app/Domain/Connector/Templates/submodules/importProgress.sub.php Removes legacy connector import progress submodule.
app/Domain/Connector/Templates/submodules/importProgress.blade.php Adds Blade connector import progress submodule.
app/Domain/Connector/Templates/show.tpl.php Removes legacy integrations listing template.
app/Domain/Connector/Templates/show.blade.php Adds Blade integrations listing page template.
app/Domain/Connector/Templates/providers.blade.php Converts providers page to Blade layout and pushes scripts.
app/Domain/Connector/Templates/newIntegration.tpl.php Removes legacy new-integration template.
app/Domain/Connector/Templates/newIntegration.blade.php Adds Blade new-integration template and includes import progress.
app/Domain/Connector/Templates/integrations.blade.php Converts integrations page to Blade layout and pushes scripts.
app/Domain/Connector/Templates/integrationImport.tpl.php Removes legacy integration import review template.
app/Domain/Connector/Templates/integrationImport.blade.php Adds Blade integration import review template.
app/Domain/Connector/Templates/integrationFields.blade.php Converts integration field mapping page to Blade layout.
app/Domain/Connector/Templates/integrationEntity.blade.php Converts integration entity mapping page to Blade layout.
app/Domain/Connector/Templates/integrationConfirm.tpl.php Removes legacy integration confirmation template.
app/Domain/Connector/Templates/integrationConfirm.blade.php Adds Blade integration confirmation template.
app/Domain/Clients/Templates/showAll.tpl.php Removes legacy clients list template.
app/Domain/Clients/Templates/showAll.blade.php Adds Blade clients list template and pushes scripts.
app/Domain/Clients/Templates/editClient.tpl.php Removes legacy edit client template.
app/Domain/Clients/Templates/editClient.blade.php Adds Blade edit client template.
app/Domain/Clients/Templates/delClient.tpl.php Removes legacy delete client template.
app/Domain/Clients/Templates/delClient.blade.php Adds Blade delete client template.
app/Domain/Canvas/Templates/showCanvasBottom.inc.php Removes legacy shared canvas bottom partial.
app/Domain/Canvas/Templates/showCanvasBottom.blade.php Adds Blade shared canvas bottom partial and inline scripts.
app/Domain/Canvas/Templates/modals.blade.php Adds empty Blade partial for legacy compatibility.
app/Domain/Canvas/Templates/helper.inc.php Removes legacy shared canvas helper partial.
app/Domain/Canvas/Templates/helper.blade.php Adds Blade shared canvas helper partial.
app/Domain/Canvas/Templates/delCanvasItem.inc.php Removes legacy shared delete-item partial.
app/Domain/Canvas/Templates/delCanvasItem.blade.php Adds Blade shared delete-item partial.
app/Domain/Canvas/Templates/delCanvas.inc.php Removes legacy shared delete-canvas partial.
app/Domain/Canvas/Templates/delCanvas.blade.php Adds Blade shared delete-canvas partial.
app/Domain/Canvas/Templates/canvasComment.inc.php Removes legacy canvas comment modal template.
app/Domain/Canvas/Templates/canvasComment.blade.php Adds Blade canvas comment modal template.
app/Domain/Canvas/Templates/boardDialog.php Removes legacy board dialog PHP template.
app/Domain/Canvas/Templates/boardDialog.blade.php Adds Blade board dialog modal template.
app/Domain/Calendar/Templates/showAllGCals.tpl.php Removes legacy Google calendars listing template.
app/Domain/Calendar/Templates/showAllGCals.blade.php Adds Blade Google calendars listing template and pushes scripts.
app/Domain/Calendar/Templates/export.tpl.php Removes legacy iCal export modal template.
app/Domain/Calendar/Templates/export.blade.php Adds Blade iCal export modal template.
app/Domain/Calendar/Templates/editEvent.tpl.php Removes legacy edit-event modal template.
app/Domain/Calendar/Templates/editEvent.blade.php Adds Blade edit-event modal template and pushes scripts.
app/Domain/Calendar/Templates/delExternalCal.tpl.php Removes legacy delete external calendar modal template.
app/Domain/Calendar/Templates/delExternalCal.blade.php Adds Blade delete external calendar modal template.
app/Domain/Calendar/Templates/delEvent.tpl.php Removes legacy delete event modal template.
app/Domain/Calendar/Templates/delEvent.blade.php Adds Blade delete event modal template.
app/Domain/Calendar/Templates/addEvent.tpl.php Removes legacy add-event modal template.
app/Domain/Calendar/Templates/addEvent.blade.php Adds Blade add-event modal template and pushes scripts.
app/Domain/Auth/Templates/resetPw.tpl.php Removes legacy reset password template.
app/Domain/Auth/Templates/resetPw.blade.php Adds Blade reset password template and pushes scripts.
app/Domain/Auth/Templates/requestPwLink.tpl.php Removes legacy request password reset link template.
app/Domain/Auth/Templates/requestPwLink.blade.php Adds Blade request password reset link template.
app/Domain/Auth/Templates/login.tpl.php Removes legacy login template.
app/Domain/Auth/Templates/login.blade.php Adds Blade login template.
app/Domain/Api/Templates/delKey.tpl.php Removes legacy API key deletion template.
app/Domain/Api/Templates/delKey.blade.php Adds Blade API key deletion template (uses @csrf).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


<div class="maincontent">
<div class="maincontentinner">
@include('connector::partials.importProgress')

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The include path does not match the converted submodule location. This PR adds app/Domain/Connector/Templates/submodules/importProgress.blade.php, so connector::partials.importProgress will likely fail view resolution at runtime. Update the include to the expected convention (e.g., connector::submodules.importProgress) or move/alias the Blade file so that connector::partials.importProgress exists.

Suggested change
@include('connector::partials.importProgress')
@include('connector::submodules.importProgress')

Copilot uses AI. Check for mistakes.
Comment on lines +88 to +93

leantime.projectsController.initProjectTable();

}
);

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This JavaScript is syntactically invalid (ready(function() { ... } ); has mismatched braces/parentheses). It will prevent initProjectTable() from running and may break subsequent scripts. Fix the $(document).ready(...) closure to a valid structure (or convert to jQuery(function(){ ... });).

Suggested change
leantime.projectsController.initProjectTable();
}
);
leantime.projectsController.initProjectTable();
});

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This template is an empty Blade view. If it is referenced by a route/controller, it will render a blank page and effectively regress the UI. Either remove the file if it’s not meant to exist, or replace it with the converted template content (likely @extends($layout) + a @section('content') implementation or an @include(...) delegate).

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This template is an empty Blade view. If it is referenced by a route/controller, it will render a blank page. Either remove it if unused or populate it with the correct Blade implementation / delegate include.

Copilot uses AI. Check for mistakes.
<td>{!! $tpl->displayLink('calendar.editGCal', $row['id'], ['id' => $row['id']]) !!}</td>
<td>{!! $tpl->displayLink('calendar.editGCal', $row['name'], ['id' => $row['id']]) !!}</td>
<td>{{ $row['url'] }}</td>
<td><span class="color: {{ $row['colorClass'] }}" style="padding:2px;">{{ $row['colorClass'] }}</span></td>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class attribute value \"color: {{ ... }}\" is not a valid CSS class name pattern (it looks like an attempted inline style). This will not apply coloring as intended. Use a real CSS class (e.g., class=\"{{ $row['colorClass'] }}\") or move the value into style (e.g., style=\"color: ...\") depending on how colorClass is meant to be used.

Suggested change
<td><span class="color: {{ $row['colorClass'] }}" style="padding:2px;">{{ $row['colorClass'] }}</span></td>
<td><span style="color: {{ $row['colorClass'] }}; padding:2px;">{{ $row['colorClass'] }}</span></td>

Copilot uses AI. Check for mistakes.

{!! $tpl->displayNotification() !!}

<form class="formModal" method="post" action="{{ BASE_URL }}/setting/editBoxLabel?module={{ $_GET['module'] }}&label={{ $_GET['label'] }}">

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This builds a POST action URL directly from $_GET values. Even though {{ }} HTML-escapes, it does not URL-encode query params, and it couples the view to raw superglobals. Prefer using request/query helpers and proper query building (e.g., using request()->query() / http_build_query / a route helper with ->withQueryString()), so special characters don’t break the URL and the view stays framework-consistent.

Suggested change
<form class="formModal" method="post" action="{{ BASE_URL }}/setting/editBoxLabel?module={{ $_GET['module'] }}&label={{ $_GET['label'] }}">
@php
$editBoxLabelAction = BASE_URL . '/setting/editBoxLabel';
$editBoxLabelQuery = http_build_query([
'module' => request()->query('module'),
'label' => request()->query('label'),
]);
@endphp
<form class="formModal" method="post" action="{{ $editBoxLabelAction . ($editBoxLabelQuery ? '?' . $editBoxLabelQuery : '') }}">

Copilot uses AI. Check for mistakes.
<strong>{{ $provider->name }}</strong>
<br /><small>Available methods: {{ implode(', ', $provider->methods) }}</small>
<br /><br />
{{ $provider->description }}

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The legacy template rendered description unescaped, while this Blade version escapes HTML. If provider descriptions contain intended markup (links/icons), this will now render as literal text and change the UI. Decide on the contract: if descriptions are trusted HTML, render with {!! ... !!} (ideally sanitized upstream); if they are meant to be plain text, ensure providers don’t supply HTML and consider updating the old behavior accordingly.

Suggested change
{{ $provider->description }}
{!! $provider->description !!}

Copilot uses AI. Check for mistakes.

<h4 class="widgettitle title-light">{!! __('subtitles.event') !!}</h4>

<form action="{{ BASE_URL }}/calendar/addEvent/" method="post" class='formModal'>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a POST form without a CSRF token. Some converted templates now use @csrf (e.g., API key deletion), so this should be made consistent to avoid CSRF vulnerabilities and potential 419/CSRF validation failures depending on middleware configuration. Add @csrf inside the form.

Suggested change
<form action="{{ BASE_URL }}/calendar/addEvent/" method="post" class='formModal'>
<form action="{{ BASE_URL }}/calendar/addEvent/" method="post" class='formModal'>
@csrf

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +8
@php
$ticket = $tpl->get('ticket');
@endphp

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $ticket assignment is not used anywhere in this template. Since this file is short and self-contained, removing the dead assignment will reduce noise and make the template easier to maintain.

Suggested change
@php
$ticket = $tpl->get('ticket');
@endphp

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +68
<script type="text/javascript">

jQuery(document).ready(function() {

if(jQuery('#searchCanvas').length > 0) {
new SlimSelect({ select: '#searchCanvas' });
}

@if(isset($_GET['closeModal']))
jQuery.nmTop().close();
@endif

leantime.{{ $canvasName }}CanvasController.setRowHeights();
leantime.canvasController.setCanvasName('{{ $canvasName }}');
leantime.canvasController.initFilterBar();

@if($login::userIsAtLeast($roles::$editor))
leantime.canvasController.initCanvasLinks();
leantime.canvasController.initUserDropdown();
leantime.canvasController.initStatusDropdown();
leantime.canvasController.initRelatesDropdown();
@else
leantime.authController.makeInputReadonly(".maincontentinner");
@endif

@if(isset($_GET['showModal']))
@php
if ($_GET['showModal'] == '') {
$modalUrl = '&type=' . array_key_first($canvasTypes);
} else {
$modalUrl = '/' . (int) $_GET['showModal'];
}
@endphp
leantime.canvasController.openModalManually("{{ BASE_URL }}/{{ $canvasName }}canvas/editCanvasItem{{ $modalUrl }}");
window.history.pushState({},document.title, '{{ BASE_URL }}/{{ $canvasName }}canvas/showCanvas/');
@endif

});

</script>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This partial emits an inline <script> directly. Since similar templates in this PR are moving scripts into @once @push('scripts'), consider doing the same here. It keeps script placement consistent with the layout (often collected near the end of the page), reduces the chance of duplicate execution if the partial is included more than once, and makes script management easier.

Suggested change
<script type="text/javascript">
jQuery(document).ready(function() {
if(jQuery('#searchCanvas').length > 0) {
new SlimSelect({ select: '#searchCanvas' });
}
@if(isset($_GET['closeModal']))
jQuery.nmTop().close();
@endif
leantime.{{ $canvasName }}CanvasController.setRowHeights();
leantime.canvasController.setCanvasName('{{ $canvasName }}');
leantime.canvasController.initFilterBar();
@if($login::userIsAtLeast($roles::$editor))
leantime.canvasController.initCanvasLinks();
leantime.canvasController.initUserDropdown();
leantime.canvasController.initStatusDropdown();
leantime.canvasController.initRelatesDropdown();
@else
leantime.authController.makeInputReadonly(".maincontentinner");
@endif
@if(isset($_GET['showModal']))
@php
if ($_GET['showModal'] == '') {
$modalUrl = '&type=' . array_key_first($canvasTypes);
} else {
$modalUrl = '/' . (int) $_GET['showModal'];
}
@endphp
leantime.canvasController.openModalManually("{{ BASE_URL }}/{{ $canvasName }}canvas/editCanvasItem{{ $modalUrl }}");
window.history.pushState({},document.title, '{{ BASE_URL }}/{{ $canvasName }}canvas/showCanvas/');
@endif
});
</script>
@once
@push('scripts')
<script type="text/javascript">
jQuery(document).ready(function() {
if(jQuery('#searchCanvas').length > 0) {
new SlimSelect({ select: '#searchCanvas' });
}
@if(isset($_GET['closeModal']))
jQuery.nmTop().close();
@endif
leantime.{{ $canvasName }}CanvasController.setRowHeights();
leantime.canvasController.setCanvasName('{{ $canvasName }}');
leantime.canvasController.initFilterBar();
@if($login::userIsAtLeast($roles::$editor))
leantime.canvasController.initCanvasLinks();
leantime.canvasController.initUserDropdown();
leantime.canvasController.initStatusDropdown();
leantime.canvasController.initRelatesDropdown();
@else
leantime.authController.makeInputReadonly(".maincontentinner");
@endif
@if(isset($_GET['showModal']))
@php
if ($_GET['showModal'] == '') {
$modalUrl = '&type=' . array_key_first($canvasTypes);
} else {
$modalUrl = '/' . (int) $_GET['showModal'];
}
@endphp
leantime.canvasController.openModalManually("{{ BASE_URL }}/{{ $canvasName }}canvas/editCanvasItem{{ $modalUrl }}");
window.history.pushState({},document.title, '{{ BASE_URL }}/{{ $canvasName }}canvas/showCanvas/');
@endif
});
</script>
@endpush
@endonce

Copilot uses AI. Check for mistakes.
- Fix include path: connector::partials.importProgress -> connector::submodules.importProgress
- Fix JS syntax error in Projects/showAll.blade.php (mismatched braces in ready())
- Fix class attribute bug in showAllGCals.blade.php (was 'class: color: ...' -> style='color: ...')
- Fix $_GET usage in editBoxDialog.blade.php action URL -> request()->query()
- Fix connector/show.blade.php description rendering: use {!! !!} since providers may contain HTML
- Add @csrf to Calendar/addEvent.blade.php POST form
- Remove unused $ticket assignment in Ideas/delCanvasItem.blade.php
- Move showCanvasBottom.blade.php script into @once @Push('scripts')
- Add clarifying comments to empty editProject/editAccount stub files
- Add null-safe defaults to canvasComment.blade.php and canvasDialog.blade.php
Converts all residual displaySubmodule() calls in blade templates to proper
Blade @include() with the correct view namespace paths:

- comments-generalComment -> @include('comments::submodules.generalComment', ['formUrl' => ...])
- tickets-ticketDetails   -> @include('tickets::submodules.ticketDetails')
- files-showAll           -> @include('files::submodules.showAll')
- tickets-timesheet       -> @include('tickets::submodules.timesheet')
- connector-importProgress -> @include('connector::submodules.importProgress')

Also fixes 6 wrong 'partials.' paths that should be 'submodules.' in:
- Ideas/ideaDialog, Clients/showClient (generalComment)
- Connector/integrationFields|Entity|Import|Confirm (importProgress)

Also converts remaining raw PHP in showTicketModal.blade.php to Blade syntax.
Copilot AI review requested due to automatic review settings April 12, 2026 20:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 297 out of 432 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +50 to +52
<a class="btn btn-primary pull-left" href="{{ BASE_URL }}/submodules.importProgress/integration?provider={{ $provider->id }}&step=fields{{ $urlAppend }}">Go Back</a>
@else
<a class="btn btn-primary right" href="{{ BASE_URL }}/submodules.importProgress/integration?provider={{ $provider->id }}&step=import">Confirm</a>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The integration navigation links point to /submodules.importProgress/integration..., which does not match the legacy route (/connector/integration...) and is very likely a broken URL. Update both the "Go Back" and "Confirm" hrefs to use the connector integration route.

Suggested change
<a class="btn btn-primary pull-left" href="{{ BASE_URL }}/submodules.importProgress/integration?provider={{ $provider->id }}&step=fields{{ $urlAppend }}">Go Back</a>
@else
<a class="btn btn-primary right" href="{{ BASE_URL }}/submodules.importProgress/integration?provider={{ $provider->id }}&step=import">Confirm</a>
<a class="btn btn-primary pull-left" href="{{ BASE_URL }}/connector/integration?provider={{ $provider->id }}&step=fields{{ $urlAppend }}">Go Back</a>
@else
<a class="btn btn-primary right" href="{{ BASE_URL }}/connector/integration?provider={{ $provider->id }}&step=import">Confirm</a>

Copilot uses AI. Check for mistakes.
<div class="row">
<div class="col-lg-8">
<h1><?php echo $tpl->__('headlines.connector'); ?> // <?= $provider->name ?></h1>
<h1>{!! __('headlines.submodules.importProgress') !!} // {{ $provider->name }}</h1>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several URLs within this template use the /submodules.importProgress/integration path, which appears to be an unintended substitution and will likely break navigation. Use the expected connector route (/connector/integration) for the form action and Back link; also the translation key headlines.submodules.importProgress looks incorrect for a page title and should be changed to the appropriate existing headline key used for connector pages.

Copilot uses AI. Check for mistakes.
<div class="maincontent">
<div class="maincontentinner">
<?php $tpl->displaySubmodule('connector-importProgress') ?>
@include('connector::submodules.importProgress')

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several URLs within this template use the /submodules.importProgress/integration path, which appears to be an unintended substitution and will likely break navigation. Use the expected connector route (/connector/integration) for the form action and Back link; also the translation key headlines.submodules.importProgress looks incorrect for a page title and should be changed to the appropriate existing headline key used for connector pages.

Copilot uses AI. Check for mistakes.
<p class="mb-2">Match the fields from your source to the corresponding fields in Leantime</p><br />

<form method="post" action="<?= BASE_URL ?>/connector/integration/?provider=<?= $provider->id ?>&step=parse<?= $urlAppend ?>">
<form method="post" action="{{ BASE_URL }}/submodules.importProgress/integration/?provider={{ $provider->id }}&step=parse{{ $urlAppend }}">

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several URLs within this template use the /submodules.importProgress/integration path, which appears to be an unintended substitution and will likely break navigation. Use the expected connector route (/connector/integration) for the form action and Back link; also the translation key headlines.submodules.importProgress looks incorrect for a page title and should be changed to the appropriate existing headline key used for connector pages.

Copilot uses AI. Check for mistakes.
</table>
<div class="left">
<a href="<?= BASE_URL ?>/connector/integration/?provider=<?= $provider->id ?>" class="btn btn-default pull-left">Back</a>
<a href="{{ BASE_URL }}/submodules.importProgress/integration/?provider={{ $provider->id }}" class="btn btn-default pull-left">Back</a>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several URLs within this template use the /submodules.importProgress/integration path, which appears to be an unintended substitution and will likely break navigation. Use the expected connector route (/connector/integration) for the form action and Back link; also the translation key headlines.submodules.importProgress looks incorrect for a page title and should be changed to the appropriate existing headline key used for connector pages.

Copilot uses AI. Check for mistakes.
<h3>Integration Success</h3>
<p>Your data was synced successfully.</p>
<br />
<a class='btn btn-default' href='{{ BASE_URL }}/submodules.importProgress/show'>Go back to integrations</a>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Go back to integrations" link points to /submodules.importProgress/show, which likely does not exist; the legacy template linked to /connector/show. Update the href to the connector show route so users can navigate back successfully.

Suggested change
<a class='btn btn-default' href='{{ BASE_URL }}/submodules.importProgress/show'>Go back to integrations</a>
<a class='btn btn-default' href='{{ BASE_URL }}/connector/show'>Go back to integrations</a>

Copilot uses AI. Check for mistakes.
<tr class='gradeA'>

<td style="padding:6px;">
<a class="" href="{{ BASE_URL }}/projects/showProject/{{ $row['id'] }}">{{ $row['name'] }}</a>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first project-name <td> is never closed before starting the next <td>, resulting in invalid table markup. Add a closing </td> after the project link to keep the table structure valid and avoid layout/JS table plugin issues.

Suggested change
<a class="" href="{{ BASE_URL }}/projects/showProject/{{ $row['id'] }}">{{ $row['name'] }}</a>
<a class="" href="{{ BASE_URL }}/projects/showProject/{{ $row['id'] }}">{{ $row['name'] }}</a>
</td>

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,12 @@
@php
$id = filter_var($_GET['id'], FILTER_SANITIZE_NUMBER_INT);

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This template reads $_GET['id'] directly in the view. Prefer passing $id from the controller (or using request()->route('id') / request()->query('id')) so the view is not coupled to PHP superglobals and routing/query shape. This also makes the template easier to test and reuse.

Suggested change
$id = filter_var($_GET['id'], FILTER_SANITIZE_NUMBER_INT);
$id = filter_var(request()->query('id'), FILTER_SANITIZE_NUMBER_INT);

Copilot uses AI. Check for mistakes.

<h4 class="widgettitle title-light">{!! __('subtitles.event') !!}</h4>

<form action="{{ BASE_URL }}/calendar/editEvent/{{ $values['id'] }}" method="post" class="formModal">

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This POST form is missing @csrf. Since addEvent.blade.php was updated to include @csrf, the edit/delete calendar forms should be consistent to avoid CSRF vulnerabilities and potential 419 errors under Laravel's CSRF middleware.

Suggested change
<form action="{{ BASE_URL }}/calendar/editEvent/{{ $values['id'] }}" method="post" class="formModal">
<form action="{{ BASE_URL }}/calendar/editEvent/{{ $values['id'] }}" method="post" class="formModal">
@csrf

Copilot uses AI. Check for mistakes.
Completes the Blade migration by removing all remaining legacy template
object method calls from .blade.php files:

- ->get('key') -> $key (direct variable, already in scope from controller)
- ->assign('formUrl', val) + displaySubmodule -> @include(..., ['formUrl' => val])
- ->assign('canvasTitle', ...) -> removed (dead code, variable already set)

71 files updated across Domain and Plugin templates. Zero ->get(),
->assign(), or displaySubmodule() calls remain in any blade file.
Copilot AI review requested due to automatic review settings April 12, 2026 20:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 297 out of 437 changed files in this pull request and generated 12 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +17
<button type="submit" class="btn btn-primary" id="saveAndClose" value="closeModal">{!! __('buttons.yes_delete') !!}</button>
<a class="btn btn-primary" href="{{ BASE_URL }}/calendar/showMyCalendar">{!! __('buttons.back') !!}</a>
@dispatchEvent('beforeFormClose')

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Back link has an unterminated href attribute (missing closing quote/brace), which will break the rendered HTML and can make subsequent markup invalid. Fix the href to properly close the Blade expression.

Copilot uses AI. Check for mistakes.
<div class="row">
<div class="col-lg-8">
<h1><?php echo $tpl->__('headlines.connector'); ?> // <?= $provider->name ?></h1>
<h1>{!! __('headlines.submodules.importProgress') !!} // {{ $provider->name }}</h1>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page uses a likely incorrect translation key (headlines.submodules.importProgress) and routes all wizard actions to /submodules.importProgress/integration/..., which looks unintended (and inconsistent with /connector/... elsewhere). Update the headline key and correct the form/back URLs to the Connector integration endpoint.

Copilot uses AI. Check for mistakes.
The arrow indicates that we will synchronize from one location to the other.<br /><br />

<form method="post" action="<?= BASE_URL ?>/connector/integration/?provider=<?= $provider->id ?>&step=fields<?= $urlAppend ?>">
<form method="post" action="{{ BASE_URL }}/submodules.importProgress/integration/?provider={{ $provider->id }}&step=fields{{ $urlAppend }}">

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page uses a likely incorrect translation key (headlines.submodules.importProgress) and routes all wizard actions to /submodules.importProgress/integration/..., which looks unintended (and inconsistent with /connector/... elsewhere). Update the headline key and correct the form/back URLs to the Connector integration endpoint.

Copilot uses AI. Check for mistakes.

<div class="left">
<a href="<?= BASE_URL ?>/connector/integration/?provider=<?= $provider->id ?>" class="btn btn-default pull-left">Back</a>
<a href="{{ BASE_URL }}/submodules.importProgress/integration/?provider={{ $provider->id }}" class="btn btn-default pull-left">Back</a>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page uses a likely incorrect translation key (headlines.submodules.importProgress) and routes all wizard actions to /submodules.importProgress/integration/..., which looks unintended (and inconsistent with /connector/... elsewhere). Update the headline key and correct the form/back URLs to the Connector integration endpoint.

Copilot uses AI. Check for mistakes.
<div class="pagetitle">
<div class="row">
<div class="col-lg-8">
<h1>{!! __('headlines.submodules.importProgress') !!} // {{ $provider->name }}</h1>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The success page uses what appears to be an invalid translation key and links back to {{ BASE_URL }}/submodules.importProgress/show, which likely should be the Connector integrations listing (e.g., /connector/show). As written, users may land on a 404 after completing an integration.

Copilot uses AI. Check for mistakes.

{!! $tpl->displayNotification() !!}

<form class="formModal" method="post" action="{{ BASE_URL }}/setting/editBoxLabel?{{ http_build_query(['module' => request()->query('module', ''), 'label' => request()->query('label', '')]) }}">

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a POST form but it does not include a CSRF token. Add @csrf inside the form to prevent CSRF vulnerabilities.

Suggested change
<form class="formModal" method="post" action="{{ BASE_URL }}/setting/editBoxLabel?{{ http_build_query(['module' => request()->query('module', ''), 'label' => request()->query('label', '')]) }}">
<form class="formModal" method="post" action="{{ BASE_URL }}/setting/editBoxLabel?{{ http_build_query(['module' => request()->query('module', ''), 'label' => request()->query('label', '')]) }}">
@csrf

Copilot uses AI. Check for mistakes.

<h4 class="widgettitle title-light">{!! __('subtitles.delete') !!}</h4>

<form method="post" action="{{ BASE_URL }}/{{ $canvasName }}canvas/delCanvas/{{ $id }}">

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This delete action submits via POST but does not include a CSRF token. Add @csrf so board deletion cannot be triggered cross-site.

Suggested change
<form method="post" action="{{ BASE_URL }}/{{ $canvasName }}canvas/delCanvas/{{ $id }}">
<form method="post" action="{{ BASE_URL }}/{{ $canvasName }}canvas/delCanvas/{{ $id }}">
@csrf

Copilot uses AI. Check for mistakes.
</div>
<div class="modal-body">
<label>{!! __('label.title_new') !!}</label><br />
<input type="text" name="canvastitle" value="{{ e($canvasTitle) }}" placeholder="{{ __('input.placeholders.enter_title_for_board') }}"

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blade {{ ... }} already escapes output; wrapping with e() can lead to double-escaping (e.g., &amp; showing as &amp;amp;). Use a single escaping mechanism (typically just {{ $canvasTitle }} here).

Suggested change
<input type="text" name="canvastitle" value="{{ e($canvasTitle) }}" placeholder="{{ __('input.placeholders.enter_title_for_board') }}"
<input type="text" name="canvastitle" value="{{ $canvasTitle }}" placeholder="{{ __('input.placeholders.enter_title_for_board') }}"

Copilot uses AI. Check for mistakes.

<div class="showDialogOnLoad" style="display:none;">

<h4 class="widgettitle title-light" style="padding-bottom: 0"><i class="fas {{ $canvasTypes[$canvasItem['box']]['icon'] }}"></i> {{ $canvasTypes[$canvasItem['box']]['title'] }}</h4>

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This directly indexes into $canvasTypes[$canvasItem['box']] without fallback, but the template itself sets defaults where box can be an empty string. That combination can trigger an undefined index/offset error. Use a safe default (null coalescing) for icon/title or ensure canvasItem['box'] is always valid before rendering this line.

Copilot uses AI. Check for mistakes.
<h5 class="subtitle">New Integration</h5>

{{ $provider->name }}<br />
{{ $provider->description }}<br /><br />

Copilot AI Apr 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the legacy template the provider description was output unescaped (allowing markup). Here it is escaped, which can break formatting if descriptions contain HTML; elsewhere (show.blade.php) the description is still rendered unescaped. Use a consistent approach across Connector templates (either sanitize and escape everywhere, or intentionally render trusted HTML with {!! ... !!}).

Suggested change
{{ $provider->description }}<br /><br />
{!! $provider->description !!}<br /><br />

Copilot uses AI. Check for mistakes.
marcelfolaron and others added 2 commits May 27, 2026 16:56
Both acceptance failures and the phpstan error trace to the tpl->blade
migration. Verified against the CI failure artifacts.

Form-token regression (acceptance: CreateUserCest::editAUser showed
"Form token incorrect"): restore Leantime's custom session form token
(formTokenName/formTokenValue) in the forms whose controllers validate
it. @csrf emitted Laravel's _token instead, breaking user edit/delete,
API key create/delete, and 2FA disable. Affected: Users/editUser,
Users/delUser, Api/apiKey, Api/delKey, TwoFA/edit.

Undefined variable (acceptance: ApiCest::createAPIKey errored with
"Undefined variable $apiKeyValues"): NewApiKey only assigns apiKeyValues
on POST, but newAPIKey.blade references it on GET. Legacy .tpl.php
tolerated undefined vars; Blade throws. Default it to false.

Connector wizard: fix URLs (/connector/integration, /connector/show) and
headline keys (headlines.connector) corrupted by a bad substitution to
"submodules.importProgress" during migration.

phpstan: remove dead, whitespace-only Tickets submodules/comments.blade
(orphan from the empty legacy comments.sub.php; real comments render via
comments::submodules.generalComment).

Minor: close stray <td> in Projects/showAll; render Connector provider
description unescaped to match legacy and show.blade; drop double-escape
in Canvas/boardDialog; null-coalesce canvas type lookup in canvasComment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…de-migration

# Conflicts:
#	app/Domain/Errors/Templates/error403.blade.php
#	app/Domain/Users/Templates/editUser.tpl.php
Copilot AI review requested due to automatic review settings May 27, 2026 21:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@marcelfolaron marcelfolaron merged commit 31acbb9 into master May 27, 2026
7 checks passed
@marcelfolaron marcelfolaron deleted the refactor/tpl-to-blade-migration branch May 27, 2026 21:22
yonas pushed a commit to yonasBSD/leantime that referenced this pull request May 30, 2026
Follow-up to Leantime#3423. That PR stopped the fatal on /clients/showClient/{id}
by guarding the never-passed $submodules variable with `?? []`, but as a
result the Discussion tab always rendered "(0)".

The Clients controller (ShowClient::getClientPageData) already assigns
$comments via CommentService::getComments('client', $id). Count that
instead, so the tab shows the real number and no longer depends on the
$submodules variable that the Blade migration (Leantime#3362) dropped. Matches how
Tickets/Wiki compute their tab counts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants